//
//  smuGraph.cpp
//  smu_test1
//
//  Created by jiayi on 16/9/26.
//
//
#include "smuCommon.hpp"
#include "smuGraph.h"
#include "smuNode.h"

void smuGraph::save( smuNode* root, vector<string>& result )
{
    map< smuNode*, bool > visibleMap;
    smuNodes temp;
    smuNodesIter iter;
    smuNode* node = nullptr;
    
    temp.push_back( root );
    
    while( !temp.empty() ){
        node = temp.front();
        temp.pop_front();
        
        if( visibleMap[ node ] ){
            continue;
        }
        // mark visible
        visibleMap[ node ] = true;
        
        for( iter = node->relyTo.begin(); iter != node->relyTo.end(); ++ iter ){
            if( !visibleMap[ (*iter) ] ){
                // root or delete node would not be saved
                if( node != root && !node->isDeleted() && !(*iter)->isDeleted() ){
                    result.push_back( node->name + " " + ( *iter )->name );
                }
                temp.push_back( *iter );
            }else{
                cout << "repeat" << endl;
            }
        }
    }

}

void smuGraph::updateBFS(smuNode *firstNode, int param )
{
    visibleMap vm;
    visibleMap visibleRelies;
    
    // update node first
    updateRelies( firstNode, param, visibleRelies );
    
    smuNodes temp;
    smuNodesIter iter;
    smuNode* node = nullptr;
    
    temp.push_back( firstNode );
    
    while( !temp.empty() ){
        node = temp.front();
        temp.pop_front();
        
        if( vm[ node ] ){
            continue;
        }
        
        // mark visible
        vm[ node ] = true;
        
        for( iter = node->relyFrom.begin(); iter != node->relyFrom.end(); ++ iter ){
            
            cout << (*iter)->name << endl;
            // update usable
            updateRelies( *iter, param, visibleRelies );
            
            // waiting for update
            if( !vm[ (*iter) ] ){
                temp.push_back( *iter );
            }
        }
    }
}

void smuGraph::updateRelies(smuNode *node, int param, visibleMap& visible )
{
    if( !node ){
        return;
    }
    visible[node] = true;
    bool usable = true;
    smuNodesIter iter = node->relyTo.begin();
    for( ; iter != node->relyTo.end(); ++ iter ){
        if( !visible[*iter] ){
            updateRelies( (*iter), param, visible );
        }
        if( !( *iter )->isAvailable() ){
            usable = false;
            break;
        }
    }
    node->setUsable( usable );
    
    if( _f ){
        _f( node, param );
    }
}

bool smuGraph::addLink( smuNode* node, smuNode* rely )
{
    if( _circle( node, rely ) ){
        return false;
    }
    // add link
    node->relyTo.push_back( rely );
    rely->relyFrom.push_back( node );
    return true;
}

bool smuGraph::_circle( smuNode* node, smuNode* to )
{
    if( node == to ){
        return true;
    }
    smuNodes temp;
    smuNodesIter iter;
    smuNode* fnode = nullptr;
    
    temp.push_back( to );
    
    while( !temp.empty() ){
        fnode = temp.front();
        temp.pop_front();
        
        for( iter = fnode->relyTo.begin(); iter != fnode->relyTo.end(); ++ iter ){
            if( (*iter) == node ){
                return true;
            }else{
                temp.push_back( *iter );
            }
        }
    }
    return false;
}
